package org.dtrd.modules.record.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dtrd.common.util.DateUtils;
import org.dtrd.config.system.Constant;
import org.dtrd.modules.achievement.service.IDtrdEntRdSigninRecordService;
import org.dtrd.modules.record.entity.bean.*;
import org.dtrd.modules.record.entity.po.DtrdEntRdSigninFoodRecord;
import org.dtrd.modules.record.mapper.DtrdEntRdFoodRecordMapper;
import org.dtrd.modules.record.service.IDtrdEntRdSigninSuggestService;
import org.dtrd.modules.record.service.IFoodRecordService;
import org.dtrd.modules.suggest.service.IDtrdEntRdSigninRecordSuggestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 萧
 * @date:2021-08-22
 **/
@Service
@DS("multi-datasource1")
@Slf4j
public class FoodRecordServiceImpl extends ServiceImpl<DtrdEntRdFoodRecordMapper, DtrdEntRdSigninFoodRecord> implements IFoodRecordService {

    @Autowired
    private IDtrdEntRdSigninRecordService signinRecordService;
    @Autowired
    private IDtrdEntRdSigninSuggestService suggestService;

    @Autowired
    private IDtrdEntRdSigninRecordSuggestService signinRecordSuggestService;

    @Override
    public DtrdEntRdSigninFoodRecord transformRecord(CheckinRecord record) {
        DtrdEntRdSigninFoodRecord dt = new DtrdEntRdSigninFoodRecord().init();
        dt.setPatientId(record.getPatientId());
        dt.setFoodRecordDesc(record.getFoodRecordDesc());
        dt.setRecordTime(parseStringAsDateTime(record.getRecordTime()));
        dt.setRecordDate(parseStringAsDate(record.getRecordTime()));
        dt.setFoodRecordRemark(record.getRemark());
        dt.setFoodRecordType(record.getFoodType() == null ? record.getSubType() : record.getFoodType());
        dt.setFoodRecordName(record.getFoodTypeName());
        dt.setRecordPhoto(record.getImages());
        return dt;
    }

    @Override
    public CheckinRecord transformPO(DtrdEntRdSigninFoodRecord po) {
        if (po == null) {
            return null;
        }
        CheckinRecord record = new CheckinRecord();
        record.setRecordTime(DateUtils.formatTime(po.getRecordTime()));
        record.setRecordTimeHm(DateUtils.formatShortTime(po.getRecordTime()));
        record.setDataId(po.getDataId());
        record.setImages(po.getRecordPhoto());
        record.setPatientId(po.getPatientId());
        record.setFoodType(po.getFoodRecordType());
        record.setFoodTypeName(po.getFoodRecordName());
        record.setRemark(po.getFoodRecordRemark());
        record.setRecordType(Constant.RecordType.DIET.getType());
        record.setRecordTypeName(Constant.RecordType.DIET.getName());
        record.setFoodRecordDesc(po.getFoodRecordDesc());
        return record;
    }

    @Override
    public LambdaQueryWrapper<DtrdEntRdSigninFoodRecord> generateSelectRecordByDateQuery(Integer patientId, String date, Integer subType) {
        LambdaQueryWrapper<DtrdEntRdSigninFoodRecord> query = new LambdaQueryWrapper<>();
        query.eq(DtrdEntRdSigninFoodRecord::getIsDel, 0)
                .eq(DtrdEntRdSigninFoodRecord::getPatientId, patientId)
                .eq(DtrdEntRdSigninFoodRecord::getRecordDate, date).eq(DtrdEntRdSigninFoodRecord::getFoodRecordType, subType);
        return query;
    }

    @Override
    public Integer getFoodRecordDateCount(Integer patientId, String startDate, String endDate) {
        return baseMapper.selectFoodRecordDateCount(patientId, startDate, endDate);
    }

    @Override
    public boolean saveFoodRecord(DietRecordBean value) {
        DtrdEntRdSigninFoodRecord newRecord = new DtrdEntRdSigninFoodRecord();
        if (value.getId() == null) {
            newRecord = newRecord.init();
        }
        try {
            newRecord.setRecordTime(DateUtils.parseDate(value.getRecordTime(), DateUtils.datetimeFormat.get().toPattern()));
            newRecord.setRecordDate(DateUtils.parseDate(value.getRecordTime(), DateUtils.date_sdf.get().toPattern()));
        } catch (ParseException e) {
            log.error("日期格式错误, 转换失败");
            e.printStackTrace();
        }
        newRecord.setPatientId(value.getPatientId());
        newRecord.setFoodRecordName(value.getName());
        newRecord.setFoodRecordType(value.getFoodRecordType());
        newRecord.setRecordPhoto(value.getRecordPhoto());
        newRecord.setFoodRecordRemark(value.getFoodRecordRemark());
        newRecord.setFoodRecordDesc(value.getFoodRecordDesc());
        LambdaUpdateWrapper<DtrdEntRdSigninFoodRecord> wrapper = Wrappers.lambdaUpdate(DtrdEntRdSigninFoodRecord.class)
                .eq(DtrdEntRdSigninFoodRecord::getPatientId, value.getPatientId())
                .eq(DtrdEntRdSigninFoodRecord::getFoodRecordType, value.getFoodRecordType())
                .eq(DtrdEntRdSigninFoodRecord::getRecordDate, newRecord.getRecordDate());
        boolean result = saveOrUpdate(newRecord, wrapper);
        log.info("FoodRecordServiceImpl.saveFoodRecord.[value] after save data_id=" + newRecord.getDataId());
        // 补充打卡记录
        if (newRecord.getDataId() == null) {
            newRecord = getOne(wrapper);
        }
        signinRecordService.saveSigninRecord(newRecord.getDataId(), value.getFoodRecordType(), mapper ->
                mapper.apply(value.getPatientId())
                        .withRecordType(Constant.RecordType.DIET.getType())
                        .withRecordTime(value.getRecordTime())
                        .withImages(value.getRecordPhoto())
                        .build()
        );
        return result;
    }

    @Override
    public List<DailyDietRecordBean> getAllGroupedFoodRecord(Integer patientId, String startDate, String endDate, Integer page, Integer pageSize) {
        List<DtrdEntRdSigninFoodRecord> list = baseMapper.getAllGroupedFoodRecord(patientId, startDate, endDate);
        if (list.size() > 0) {
            List<DailyDietRecordBean> dataList = new ArrayList<>(list.size() / 2);
            // 转换成 date : 各阶段photo 的映射
            TreeMap<String, List<DtrdEntRdSigninFoodRecord>> recordMap = new TreeMap<>(Collections.reverseOrder());
            list.forEach(value -> {
                String date = DateUtils.formatDate(value.getRecordDate());
                List<DtrdEntRdSigninFoodRecord> dateRecordList = recordMap.get(date);
                if (dateRecordList == null) {
                    dateRecordList = new ArrayList<>(6);
                }
                dateRecordList.add(value);
                recordMap.put(date, dateRecordList);
            });
            if (MapUtil.isNotEmpty(recordMap)) {
                Set<String> keySet = recordMap.keySet();
                keySet.forEach(date -> {
                    DailyDietRecordBean dailyDietRecordBean = new DailyDietRecordBean();
                    dailyDietRecordBean.setDate(date);
                    dailyDietRecordBean.setPatientId(patientId);

                    // 增加指定日期以前最近的饮食建议 肖 2022-08-04 11:05:32
//                    DtrdEntRdSigninSuggest suggest = suggestService.getLatestSuggest(patientId, date);
//                    dailyDietRecordBean.setSuggestInfo(Optional.ofNullable(suggest).map(DtrdEntRdSigninSuggest::getSuggestContent).orElse(null));

                    List<DtrdEntRdSigninFoodRecord> dataRecord = recordMap.get(date);
                    for (DtrdEntRdSigninFoodRecord foodRecord : dataRecord) {
                        Constant.FoodRecordType foodRecordType = Constant.FoodRecordType.valueOf(foodRecord.getFoodRecordType());
                        DietRecordBean dietRecordBean = new DietRecordBean().parseFromPo(foodRecord);
                        dietRecordBean.setSigninRecordSuggestListInfo(signinRecordSuggestService.getSigninRecordSuggestListById(foodRecord.getDataId()));
                        assert foodRecordType != null;
                        switch (foodRecordType) {
                            case BREAKFAST:
                                dailyDietRecordBean.setBreakfastPhoto(foodRecord.getRecordPhoto());
                                dailyDietRecordBean.setBreakfastRecord(dietRecordBean);
                                break;
                            case LUNCH:
                                dailyDietRecordBean.setLunchPhoto(foodRecord.getRecordPhoto());
                                dailyDietRecordBean.setLunchRecord(dietRecordBean);
                                break;
                            case DINNER:
                                dailyDietRecordBean.setDinnerPhoto(foodRecord.getRecordPhoto());
                                dailyDietRecordBean.setDinnerRecord(dietRecordBean);
                                break;
                            case EXTRABREAKFAST:
                                dailyDietRecordBean.setExtraBreakfastPhoto(foodRecord.getRecordPhoto());
                                dailyDietRecordBean.setExtraBreakfast(dietRecordBean);
                                break;
                            case EXTRALUNCH:
                                dailyDietRecordBean.setExtraLunchPhoto(foodRecord.getRecordPhoto());
                                signinRecordSuggestService.getSigninRecordSuggestListById(foodRecord.getDataId());
                                dailyDietRecordBean.setExtraLunchRecord(dietRecordBean);
                                break;
                            case EXTRADINNER:
                                dailyDietRecordBean.setExtraDinnerPhoto(foodRecord.getRecordPhoto());
                                dailyDietRecordBean.setExtraDinnerLunchRecord(dietRecordBean);
                                break;
                            default:
                                break;
                        }
                    }

                    // 添加评分建议
//                    SigninRecordSuggestListRequest recordSuggestListRequest = new SigninRecordSuggestListRequest();
//                    recordSuggestListRequest.setRecordDate(date);
//                    List<SigninRecordSuggestListInfo> recordSuggestList = signinRecordSuggestService.getSigninRecordSuggestListByDate(date, patientId, Constant.SuggestType.DIET.getType());
//                    dailyDietRecordBean.setSigninRecordSuggestListInfo(recordSuggestList);
                    dataList.add(dailyDietRecordBean);
                });
                // controller 层会有默认的 page, pageSize
                assert page != null;
                assert pageSize != null;
                int pageStart = (page - 1) * pageSize;
                ArrayList<DailyDietRecordBean> resultList = new ArrayList<>(pageSize);
                int range = Math.min(page * pageSize, dataList.size());
                for (int i = pageStart; i < range; i++) {
                    resultList.add(dataList.get(i));
                }
                return resultList;
            }
        }
        return Collections.EMPTY_LIST;
    }

    @Override
    public List<DietListInfo> getFoodRecordList(Integer patientId, String startDate, String endDate) {
        LambdaQueryWrapper<DtrdEntRdSigninFoodRecord> queryWrapper = Wrappers.lambdaQuery(DtrdEntRdSigninFoodRecord.class)
                .eq(DtrdEntRdSigninFoodRecord::getPatientId, patientId)
                .ge(DtrdEntRdSigninFoodRecord::getRecordDate, startDate)
                .le(DtrdEntRdSigninFoodRecord::getRecordDate, endDate)
                .orderByDesc(DtrdEntRdSigninFoodRecord::getRecordDate)
                .orderByAsc(DtrdEntRdSigninFoodRecord::getFoodRecordType);
        List<DtrdEntRdSigninFoodRecord> poList = list(queryWrapper);
        List<DietListInfo> dtoList = new ArrayList<>(poList.size());
        if (CollectionUtil.isNotEmpty(poList)) {
            dtoList = poList.stream()
                    .map(po -> new DietListInfo().parseFromPo(po))
                    .collect(Collectors.toList());
        }
        return dtoList;
    }

    @Override
    public DailySigninDietStatus getPatientDailySigninDietStatus(Integer patientId, Date dateYMD) {
        LambdaQueryWrapper<DtrdEntRdSigninFoodRecord> wrapper = Wrappers.lambdaQuery(DtrdEntRdSigninFoodRecord.class)
                .eq(DtrdEntRdSigninFoodRecord::getPatientId, patientId)
                .eq(DtrdEntRdSigninFoodRecord::getRecordDate, DateUtils.getDateYMD())
                .orderByAsc(DtrdEntRdSigninFoodRecord::getFoodRecordType);
        List<DtrdEntRdSigninFoodRecord> foodRecords = list(wrapper);
        if (CollectionUtil.isNotEmpty(foodRecords)) {
            DailySigninDietStatus status = new DailySigninDietStatus();
            for (DtrdEntRdSigninFoodRecord foodRecord : foodRecords) {
                Constant.FoodRecordType foodRecordType = Constant.FoodRecordType.valueOf(foodRecord.getFoodRecordType());
                assert foodRecordType != null;
                switch (foodRecordType) {
                    case BREAKFAST:
                        status.setBreakfast(true);
                        status.setBreakfastPhoto(foodRecord.getRecordPhoto());
                        break;
                    case LUNCH:
                        status.setLunch(true);
                        status.setLunchPhoto(foodRecord.getRecordPhoto());
                        break;
                    case DINNER:
                        status.setDinner(true);
                        status.setDinnerPhoto(foodRecord.getRecordPhoto());
                        break;
                }
            }
            return status;
        }
        return null;
    }
}
